/*
 * cmd_efuse_simple_test.c
 *
 *  Created on: Nov 10, 2016
 *      Author: duobao
 */


/*
 * cmd_efuse_test.c
 *
 *  Created on: Sep 28, 2016
 *      Author: duobao
 */
#ifdef CONFIG_FH_AES_V2
#include "../drivers/crypto/fh_aes_v2.h"
#else
#include "../drivers/crypto/fh_aes.h"
#endif
#include <common.h>
#include <command.h>

//#define FH_EFUSE_TOOLS_DEBUG printf
#define FH_EFUSE_TOOLS_DEBUG(...)

#define EFUSE_MAX_ENTRY_SIZE	64
static unsigned int matchkey = 0x92fc0025;
struct efuse_head {
	unsigned int chipid;
	unsigned int data_cnt;
	unsigned int filesize;
	unsigned int reserved[5];
};

struct efuse_data_head {
	unsigned int startentry;
	unsigned int datasize;
	unsigned int readbackcheck;
	unsigned int reserved[5];
};


void parse_efuse_data_head(struct efuse_data_head *p_ef_dhead, unsigned char * p_data_add){
	int i;
	unsigned char *p_uchar;
	struct wrap_efuse_obj *p_efuse;
	unsigned int entry;
	FH_EFUSE_TOOLS_DEBUG("entry : datasize : readback  = %x : %x : %x\n",p_ef_dhead->startentry,p_ef_dhead->datasize,p_ef_dhead->readbackcheck);
	p_uchar = p_data_add;
	entry = p_ef_dhead->startentry;
	FH_EFUSE_TOOLS_DEBUG("data add is %x\n",(int)p_uchar);
	p_efuse = (struct wrap_efuse_obj *)get_efuse_handle();
	for(i = 0; i < p_ef_dhead->datasize; i++){
		refresh_efuse(p_efuse);
		efuse_write_key_byte(p_efuse, entry++,*p_uchar++);
	}
	FH_EFUSE_TOOLS_DEBUG("\n");
}


int efuse_bin_write(cmd_tbl_t *cmdtp,int flag,int argc,char *argv[])
{
	unsigned int addr;
	struct efuse_head ef_head = {0};
	struct efuse_data_head ef_dhead = {0};
	void *p_ef_dhead;
	unsigned int i;
	if (argc != 2) {
		cmd_usage(cmdtp);
		return -1;
	}
	addr = simple_strtoul(argv[1], NULL, 16);
	FH_EFUSE_TOOLS_DEBUG("[efuse tool] : addr is %x\n",addr);
	memcpy(&ef_head, (void*)addr, sizeof(struct efuse_head));
	p_ef_dhead = (void *)(addr + sizeof(struct efuse_head));
	for(i = 0; i < ef_head.data_cnt; i++){
		memcpy(&ef_dhead, p_ef_dhead, sizeof(struct efuse_data_head));
		FH_EFUSE_TOOLS_DEBUG("cp add is : data start entry : size : read back check = %x : %x : %x : %x\n",
		(int)p_ef_dhead, ef_dhead.startentry,ef_dhead.datasize,ef_dhead.readbackcheck);
		/* parse ef_data*/
		parse_efuse_data_head(&ef_dhead, (unsigned char*)((int)p_ef_dhead + sizeof(struct efuse_data_head)));
		/* update ef data point*/
		p_ef_dhead = (void*)((int)p_ef_dhead + sizeof(struct efuse_data_head) + ef_dhead.datasize);

	}

	return 0;
}

U_BOOT_CMD(

	efuse_bin_write,5,1,efuse_bin_write,"usage:efuse bin write\n"," bin_mem_addr\n"

);


int efuse_dump_entry_map(cmd_tbl_t *cmdtp,int flag,int argc,char *argv[])
{
	unsigned int addr, st_entry, size;
	char *endp;
	struct wrap_efuse_obj *p_efuse;
	if (argc != 4) {
		cmd_usage(cmdtp);
		return -1;
	}

	addr = simple_strtoul(argv[1], NULL, 16);
	st_entry = simple_strtoul(argv[2], NULL, 16);
	size = simple_strtoul(argv[3], NULL, 16);
	FH_EFUSE_TOOLS_DEBUG("[efuse tool] : addr is %x; st_entry : %x; size : %x\n",addr,st_entry,size);
	p_efuse = (struct wrap_efuse_obj *)get_efuse_handle();
	refresh_efuse(p_efuse);
	efuse_read_entry(p_efuse, matchkey, st_entry, (unsigned char*)addr, size);

	return 0;

}

U_BOOT_CMD(

	efuse_dump_entry_map,5,1,efuse_dump_entry_map,"usage:efuse dump entry map\n","mem_addr efuse_entry_start dump_efuse_size\n"

);

#ifdef CONFIG_FH_AES_V2
int efuse_write_entry_map(cmd_tbl_t *cmdtp,int flag,int argc,char *argv[])
{
	EFUSE_INFO_V2 efuse_info;
	u32 mem_add;
	u32 entry_no;
	u32 entry_size;

	mem_add = simple_strtoul(argv[1], NULL, 16);
	entry_no = simple_strtoul(argv[2], NULL, 16);
	entry_size = simple_strtoul(argv[3], NULL, 16);
	FH_EFUSE_TOOLS_DEBUG("mem : entry : size = %08x : %08x : %08x\n",mem_add, entry_no, entry_size);
	memset(&efuse_info, 0, sizeof(EFUSE_INFO_V2));
	if (argc != 4) {
		cmd_usage(cmdtp);
		return -1;
	}
	fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_CHECK_PRO, 0);


    efuse_info.efuse_entry_no = entry_no;
    efuse_info.key_buff =(unsigned char*)mem_add;
    efuse_info.key_size = entry_size;

    fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_WRITE_ENTRY, 0);

	return 0;
}

U_BOOT_CMD(

	efuse_write_entry_map,5,1,efuse_write_entry_map,"usage:efuse write entry map\n","write_mem_add efuse_entry_pos entry_size(byte)\n"

);

int efuse_read_entry_map(cmd_tbl_t *cmdtp,int flag,int argc,char *argv[])
{

	EFUSE_INFO_V2 efuse_info;
	u32 mem_add;
	u32 entry_no;
	u32 entry_size;

	mem_add = simple_strtoul(argv[1], NULL, 16);
	entry_no = simple_strtoul(argv[2], NULL, 16);
	entry_size = simple_strtoul(argv[3], NULL, 16);
	FH_EFUSE_TOOLS_DEBUG("mem : entry : size = %08x : %08x : %08x\n",mem_add, entry_no, entry_size);
	memset(&efuse_info, 0, sizeof(EFUSE_INFO_V2));
	if (argc != 4) {
		cmd_usage(cmdtp);
		return -1;
	}

    efuse_info.efuse_entry_no = entry_no;
    efuse_info.key_buff =(unsigned char*)mem_add;
    efuse_info.key_size = entry_size;
    efuse_info.status.error = matchkey;

    fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_READ_ENTRY, 0);

	return 0;
}

U_BOOT_CMD(

	efuse_read_entry_map,5,1,efuse_read_entry_map,"usage:efuse read entry map\n","read_mem_add efuse_entry_pos entry_size(byte)\n"

);

int efuse_set_read_lock(cmd_tbl_t *cmdtp,int flag,int argc,char *argv[])
{

	EFUSE_INFO_V2 efuse_info;
	u32 aes_lock;
	u32 efuse_lock;


	if (argc != 3) {
		cmd_usage(cmdtp);
		return -1;
	}

	aes_lock = simple_strtoul(argv[1], NULL, 16);
	efuse_lock = simple_strtoul(argv[2], NULL, 16);
	FH_EFUSE_TOOLS_DEBUG("aes_lock : efuse_lock = %08x : %08x : %08x\n",aes_lock, efuse_lock);
	memset(&efuse_info, 0, sizeof(EFUSE_INFO_V2));
    efuse_info.status.efuse_apb_lock = efuse_lock;
    efuse_info.status.aes_ahb_lock = aes_lock;
    fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_SET_LOCK_DATA, 0);

	return 0;
}

U_BOOT_CMD(

	efuse_set_read_lock,5,1,efuse_set_read_lock,"usage:efuse set read lock\n"," aes_lock(bit(x) = key(x) & key(x+1)) efuse_lock(one bit = 4BLK, 1BLK = 4 entry), bit 14 only lock BLK56\n"

);


int efuse_set_write_lock(cmd_tbl_t *cmdtp,int flag,int argc,char *argv[])
{
	EFUSE_INFO_V2 efuse_info;
	u32 write_lock_lo;
	u32 write_lock_hi;

	if (argc != 3) {
		cmd_usage(cmdtp);
		return -1;
	}

	write_lock_lo = simple_strtoul(argv[1], NULL, 16);
	write_lock_hi = simple_strtoul(argv[2], NULL, 16);
	FH_EFUSE_TOOLS_DEBUG("write_lock_lo : write_lock_hi = %08x : %08x\n",write_lock_lo, write_lock_hi);
	memset(&efuse_info, 0, sizeof(EFUSE_INFO_V2));
    efuse_info.status.efuse_write_lock[0] = write_lock_lo;
    efuse_info.status.efuse_write_lock[1] = write_lock_hi;
    fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_SET_LOCK_WRITE_DATA, 0);

	return 0;
}

U_BOOT_CMD(

	efuse_set_write_lock,5,1,efuse_set_write_lock,"usage:efuse set write lock\n"," write_lock_low(one bit = 1BLK, 1BLK = 4 entry) write_lock_high\n"

);


int efuse_write_bit(cmd_tbl_t *cmdtp,int flag,int argc,char *argv[])
{
	EFUSE_INFO_V2 efuse_info;
	u32 entry;
	u32 bit_pos;
	u32 bit_val;

	if (argc != 4) {
		cmd_usage(cmdtp);
		return -1;
	}

	entry = simple_strtoul(argv[1], NULL, 10);
	bit_pos = simple_strtoul(argv[2], NULL, 16);
	bit_val = simple_strtoul(argv[3], NULL, 16);
	if(bit_val > 1){
		FH_EFUSE_TOOLS_DEBUG("err bit val %x\n",bit_val);
		return -1;
	}	
	FH_EFUSE_TOOLS_DEBUG("entry : bit_pos : bit_val= %08x : %08x : %08x\n",entry, bit_pos, bit_val);
	memset(&efuse_info, 0, sizeof(EFUSE_INFO_V2));
	efuse_info.efuse_entry_no = entry;
    efuse_info.bit_pos = bit_pos;
    efuse_info.bit_val = bit_val;
    fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_WRITE_BIT, 0);

	return 0;
}

U_BOOT_CMD(

	efuse_write_bit,5,1,efuse_write_bit,"usage:efuse write entry with bit\n"," entry bit_pos bit_val\n"

);


int efuse_cmp_func(cmd_tbl_t *cmdtp,int flag,int argc,char *argv[])
{
	EFUSE_INFO_V2 efuse_info;
	u32 mem_add;
	u32 blk_start;
	u32 cmp_bit;
	if (argc != 4) {
		cmd_usage(cmdtp);
		return -1;
	}

	mem_add = simple_strtoul(argv[1], NULL, 16);
	blk_start = simple_strtoul(argv[2], NULL, 16);
	cmp_bit = simple_strtoul(argv[3], NULL, 16);
	FH_EFUSE_TOOLS_DEBUG("mem_addr : blk_start : cmp_bits = %08x : %08x : %d\n", mem_add, blk_start, cmp_bit);
	memset(&efuse_info, 0, sizeof(EFUSE_INFO_V2));
	efuse_info.efuse_entry_no = blk_start;
	efuse_info.key_buff =(unsigned char*)mem_add;
	efuse_info.key_size = cmp_bit / 8;
	fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_MEM_CMP, 0);

	return 0;
}

U_BOOT_CMD(
	efuse_cmp_func,4,1,efuse_cmp_func,"usage:efuse cmp mem \n"," memadd efuse_start_blk cmp_bits\n"
);

int efuse_write_key_map(cmd_tbl_t *cmdtp,int flag,int argc,char *argv[])
{
	EFUSE_INFO_V2 efuse_info;
	u32 mem_add;
	u32 entry_no;
	u32 entry_size;
	u32 i, status;

	mem_add = simple_strtoul(argv[1], NULL, 16);
	entry_no = simple_strtoul(argv[2], NULL, 16);
	entry_size = simple_strtoul(argv[3], NULL, 16);
	FH_EFUSE_TOOLS_DEBUG("mem : entry : size = %08x : %08x : %08x\n",mem_add, entry_no, entry_size);
	memset(&efuse_info, 0, sizeof(EFUSE_INFO_V2));
	if (argc != 4) {
		cmd_usage(cmdtp);
		return -1;
	}
	fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_CHECK_PRO, 0);
	for (i = entry_no; i < entry_no + entry_size; i += 4) {
		status = efuse_info.status.protect_bits[(i / 128)];
		if (!(status & (0x01 << ((i >> 2) % 32)))) {
			printf("entry[%d] cannot be writen. status=0x%x\n", i, status);
			return -2;
		}
	}

    efuse_info.efuse_entry_no = entry_no;
    efuse_info.key_buff =(unsigned char*)mem_add;
    efuse_info.key_size = entry_size;

    fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_WRITE_KEY, 0);

	return 0;
}

U_BOOT_CMD(

	efuse_write_key_map,5,1,efuse_write_key_map,"usage:efuse write key map\n","write_mem_add efuse_entry_pos entry_size(byte)\n"

);

int efuse_read_key_map(cmd_tbl_t *cmdtp,int flag,int argc,char *argv[])
{
	EFUSE_INFO_V2 efuse_info;
	u32 mem_add;
	u32 entry_no;
	u32 entry_size;

	mem_add = simple_strtoul(argv[1], NULL, 16);
	entry_no = simple_strtoul(argv[2], NULL, 16);
	entry_size = simple_strtoul(argv[3], NULL, 16);
	FH_EFUSE_TOOLS_DEBUG("mem : entry : size = %08x : %08x : %08x\n",mem_add, entry_no, entry_size);
	memset(&efuse_info, 0, sizeof(EFUSE_INFO_V2));
	if (argc != 4) {
		cmd_usage(cmdtp);
		return -1;
	}

    efuse_info.efuse_entry_no = entry_no;
    efuse_info.key_buff =(unsigned char*)mem_add;
    efuse_info.key_size = entry_size;
    efuse_info.status.error = matchkey;

    fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_READ_KEY, 0);

	return 0;
}

U_BOOT_CMD(

	efuse_read_key_map,5,1,efuse_read_key_map,"usage:efuse read key map\n","read_mem_addr efuse_entry_start efuse_key_size\n"

);
#else
int efuse_write_entry_map(cmd_tbl_t *cmdtp,int flag,int argc,char *argv[])
{
	EFUSE_INFO efuse_info;
	u32 mem_add;
	u32 entry_no;
	u32 entry_size;
	u32 i, status;

	mem_add = simple_strtoul(argv[1], NULL, 16);
	entry_no = simple_strtoul(argv[2], NULL, 16);
	entry_size = simple_strtoul(argv[3], NULL, 16);
	FH_EFUSE_TOOLS_DEBUG("mem : entry : size = %08x : %08x : %08x\n",mem_add, entry_no, entry_size);
	memset(&efuse_info, 0, sizeof(EFUSE_INFO));
	if (argc != 4) {
		cmd_usage(cmdtp);
		return -1;
	}
	fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_CHECK_PRO, 0);
	for (i = entry_no; i < entry_no + entry_size; i++) {
		status = efuse_info.status.protect_bits[(i / 32)];
		if (!(status & (0x01 << (i % 32)))) {
			printf("entry[%d] cannot be writen. status=0x%x\n", i, status);
			return -2;
		}
	}

    efuse_info.efuse_entry_no = entry_no;
    efuse_info.key_buff =(unsigned char*)mem_add;
    efuse_info.key_size = entry_size;

    fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_WRITE_ENTRY, 0);

	return 0;
}

U_BOOT_CMD(

	efuse_write_entry_map,5,1,efuse_write_entry_map,"usage:efuse write entry map\n","write_mem_add efuse_entry_pos entry_size(byte)\n"

);

int efuse_read_entry_map(cmd_tbl_t *cmdtp,int flag,int argc,char *argv[])
{

	EFUSE_INFO efuse_info;
	u32 mem_add;
	u32 entry_no;
	u32 entry_size;

	mem_add = simple_strtoul(argv[1], NULL, 16);
	entry_no = simple_strtoul(argv[2], NULL, 16);
	entry_size = simple_strtoul(argv[3], NULL, 16);
	FH_EFUSE_TOOLS_DEBUG("mem : entry : size = %08x : %08x : %08x\n",mem_add, entry_no, entry_size);
	memset(&efuse_info, 0, sizeof(EFUSE_INFO));
	if (argc != 4) {
		cmd_usage(cmdtp);
		return -1;
	}

    efuse_info.efuse_entry_no = entry_no;
    efuse_info.key_buff =(unsigned char*)mem_add;
    efuse_info.key_size = entry_size;
    efuse_info.status.error = matchkey;

    fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_READ_ENTRY, 0);

	return 0;
}

U_BOOT_CMD(

	efuse_read_entry_map,5,1,efuse_read_entry_map,"usage:efuse read entry map\n","read_mem_add efuse_entry_pos entry_size(byte)\n"

);

int efuse_write_key_map(cmd_tbl_t *cmdtp,int flag,int argc,char *argv[])
{
	EFUSE_INFO efuse_info;
	u32 mem_add;
	u32 entry_no;
	u32 entry_size;
	u32 i, status;

	mem_add = simple_strtoul(argv[1], NULL, 16);
	entry_no = simple_strtoul(argv[2], NULL, 16);
	entry_size = simple_strtoul(argv[3], NULL, 16);
	FH_EFUSE_TOOLS_DEBUG("mem : entry : size = %08x : %08x : %08x\n",mem_add, entry_no, entry_size);
	memset(&efuse_info, 0, sizeof(EFUSE_INFO));
	if (argc != 4) {
		cmd_usage(cmdtp);
		return -1;
	}
	fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_CHECK_PRO, 0);
	for (i = entry_no; i < entry_no + entry_size; i++) {
		status = efuse_info.status.protect_bits[(i / 32)];
		if (!(status & (0x01 << (i % 32)))) {
			printf("entry[%d] cannot be writen. status=0x%x\n", i, status);
			return -2;
		}
	}

    efuse_info.efuse_entry_no = entry_no;
    efuse_info.key_buff =(unsigned char*)mem_add;
    efuse_info.key_size = entry_size;

    fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_WRITE_KEY, 0);

	return 0;
}

U_BOOT_CMD(

	efuse_write_key_map,5,1,efuse_write_key_map,"usage:efuse write key map\n","write_mem_add efuse_entry_pos entry_size(byte)\n"

);

int efuse_read_key_map(cmd_tbl_t *cmdtp,int flag,int argc,char *argv[])
{
	EFUSE_INFO efuse_info;
	u32 mem_add;
	u32 entry_no;
	u32 entry_size;

	mem_add = simple_strtoul(argv[1], NULL, 16);
	entry_no = simple_strtoul(argv[2], NULL, 16);
	entry_size = simple_strtoul(argv[3], NULL, 16);
	FH_EFUSE_TOOLS_DEBUG("mem : entry : size = %08x : %08x : %08x\n",mem_add, entry_no, entry_size);
	memset(&efuse_info, 0, sizeof(EFUSE_INFO));
	if (argc != 4) {
		cmd_usage(cmdtp);
		return -1;
	}

    efuse_info.efuse_entry_no = entry_no;
    efuse_info.key_buff =(unsigned char*)mem_add;
    efuse_info.key_size = entry_size;
    efuse_info.status.error = matchkey;

    fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_READ_KEY, 0);

	return 0;
}

U_BOOT_CMD(

	efuse_read_key_map,5,1,efuse_read_key_map,"usage:efuse read key map\n","read_mem_addr efuse_entry_start efuse_key_size\n"

);

int efuse_set_read_lock(cmd_tbl_t *cmdtp,int flag,int argc,char *argv[])
{

	EFUSE_INFO efuse_info;
	u32 aes_lock;
	u32 efuse_lock;


	if (argc != 3) {
		cmd_usage(cmdtp);
		return -1;
	}

	aes_lock = simple_strtoul(argv[1], NULL, 16);
	efuse_lock = simple_strtoul(argv[2], NULL, 16);
	FH_EFUSE_TOOLS_DEBUG("aes_lock : efuse_lock = %08x : %08x : %08x\n",aes_lock, efuse_lock);
	memset(&efuse_info, 0, sizeof(EFUSE_INFO));
    efuse_info.status.efuse_apb_lock = efuse_lock;
    efuse_info.status.aes_ahb_lock = aes_lock;
    fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_SET_LOCK_DATA, 0);

	return 0;
}

U_BOOT_CMD(

	efuse_set_read_lock,5,1,efuse_set_read_lock,"usage:efuse set read lock\n"," aes_lock(bit(x) = key(x) & key(x+1)) efuse_lock(one bit = 4BLK, 1BLK = 4 entry), bit 14 only lock BLK56\n"

);

#endif
